<?php

class Database_Pdo extends PDO
{

    public static function exception_handler(Exception $exception)
    {
        die('Database Exception');

    }

    public function __construct($dsn, $username = '', $password = '', $driver_options = array())
    {

        set_exception_handler(array(__CLASS__, 'exception_handler'));

        parent::__construct($dsn, $username, $password, $driver_options);

        restore_exception_handler();

    }

    public function create($table, $dataArray = array())
    {
        if ($this->checkTableExists($table))
        {
            if (array_filter($dataArray, 'is_array'))
            {

                foreach ($dataArray as $row)
                {
                    $results[] = $this->create($table, $row);
                }

                return $results;
            } else
            {
                $dataArray = $this->filterTableColumnArray($table, $dataArray);

                $columns = array();

                if (count($dataArray) == 0)
                {
                    return FALSE;
                }

                $placeHolderArray = array();

                $executeArray = array();

                foreach ($dataArray as $k => $v)
                {
                    $columns[] = '`' . $k . '`';

                    $placeHolderArray[] = ':' . $k;

                    $executeArray[':' . $k] = $v;
                }

                $query = "INSERT INTO `$table` (" . implode(' , ', $columns) . ") VALUES (" . implode(' , ', $placeHolderArray) . ")";

                $sth = $this->prepare($query);

                return $sth->execute($executeArray);
            }
        }

    }

    public function deleteBy($table, $conditionArray = array())
    {

        if ($condition = $this->cleanConditionArray($table, $conditionArray))
        {

            $query = sprintf("DELETE FROM `%s` %s %s", $table, $condition);

            return $this->execute($query);
        }

        return FALSE;

    }

    public function getBy($table, $conditionArray = array(), $extras = array())
    {

        if ($condition = $this->cleanConditionArray($table, $conditionArray))
        {
            $extras = (is_array($extras) && count($extras) > 0) ? implode(' ', $extras) : '';

            return $this->query(sprintf("SELECT *  FROM %s %s", $table, $condition, $extras));
        }

        return FALSE;

    }

    public function cleanConditionArray($table, $conditionArray = array(), $returnArray = FALSE)
    {
        if ($this->checkTableExists($table))
        {
            if (!is_array($conditionArray) || count($conditionArray) == 0)
            {
                return FALSE;
            }

            foreach ($conditionArray as $cKey => $cValue)
            {
                $cValueArray = Util::trimArray(explode(' ', $cValue));

                if (count($cValueArray) != 3 || !$this->filterTableColumn($table, $cValueArray[0]))
                {
                    continue;
                }

                $conditionArray[trim($cKey)] = sprintf("`%s` %s %s", $cValueArray[0], strtoupper($cValueArray[1]), $cValueArray[2]);
            }

            return $returnArray ? $conditionArray : ' WHERE ' . implode(' AND ', $conditionArray);
        }

        return FALSE;

    }

    public function updateBy($table, $dataArray, $pkArray = array())
    {
        if ($this->checkTableExists($table))
        {

            $whereArray = array();

            foreach ($pkArray as $k => $v)
            {
                if (!$this->filterTableColumn($table, $k))
                {
                    unset($pkArray[$k]);
                } else
                {
                    $whereArray[] = $this->escape("%r = %s", $k, $v);
                }
            }

            if (count($whereArray) == 0)
                return FALSE;

            $valueArray = array();

            foreach ($dataArray as $dK => $dV)
            {
                if (!$this->filterTableColumn($table, $dK))
                {
                    unset($dataArray[$k]);
                } else
                {
                    $valueArray[] = $this->escape("%r = %s", $dK, $dV);
                }
            }

            if (count($valueArray) == 0)
                return FALSE;

            $updateQuery = sprintf('UPDATE `%s`
                                    SET 
                                    %s
                                    WHERE
                                    %s', $table, implode(' AND ', $valueArray), implode(' AND ', $whereArray));

            return $this->execute($updateQuery);
        }

        return FALSE;

    }

    public function checkTableExists($table)
    {
        $query = sprintf("SHOW TABLES");

        $result = $this->query($query);

        $tablesArray = array();

        foreach ($result as $row)
        {
            $tablesArray[] = $row['Tables_in_seatsrus'];
        }

        return in_array($table, $tablesArray);

    }

    private function getTablePk($table)
    {
        $returnValue = FALSE;

        $query = sprintf("SELECT k.column_name
            
                          FROM information_schema.table_constraints t

                          JOIN information_schema.key_column_usage k

                          USING(constraint_name,table_schema,table_name)

                          WHERE t.constraint_type='PRIMARY KEY'

                          AND t.table_name='%s'", $table);

        $result = $this->query($query);

        foreach ($result as $row)
        {
            $returnValue[] = $row['column_name'];
        }

        return $returnValue;

    }

    private function filterTableColumnArray($table, $array)
    {
        $returnArray = array();

        $checkIsMultiDArray = array_filter($array, 'is_array');

        if (count($checkIsMultiDArray) > 0)
        {
            return $array;
        }

        foreach ($array as $k => $v)
        {
            if ($this->filterTableColumn($table, $k))
            {
                $returnArray[$k] = $v;
            }
        }

        return $returnArray;

    }

    private function filterTableColumn($table, $column)
    {
        if ($this->checkTableExists($table))
        {
            $query = sprintf("SHOW COLUMNS FROM `%s`", $table);

            $result = $this->query($query);

            foreach ($result as $row)
            {
                if ($row['Field'] == $column)
                {
                    return TRUE;
                }
            }
        }

        return FALSE;

    }

}